from dtrader import dataseries


class BarDataSeries(dataseries.SequenceDataSeries):
    """A DataSeries of :class:`bar.Bar` instances.
    :param maxLen: The maximum number of values to hold.
        Once a bounded length is full, when new items are added, a corresponding number of items are discarded from the
        opposite end. If None then dataseries.DEFAULT_MAX_LEN is used.
    :type maxLen: int.
    """

    def __init__(self, max_len=None):
        super(BarDataSeries, self).__init__(max_len)
        self.__open_ds = dataseries.SequenceDataSeries(max_len)
        self.__close_ds = dataseries.SequenceDataSeries(max_len)
        self.__high_ds = dataseries.SequenceDataSeries(max_len)
        self.__low_ds = dataseries.SequenceDataSeries(max_len)
        self.__volume_ds = dataseries.SequenceDataSeries(max_len)
        self.__adj_close_ds = dataseries.SequenceDataSeries(max_len)
        self.__extra_ds = {}
        self.__use_adjusted_values = False

    def __get_or_create_extra_ds(self, name):
        ret = self.__extra_ds.get(name)
        if ret is None:
            ret = dataseries.SequenceDataSeries(self.get_max_len())
            self.__extra_ds[name] = ret
        return ret

    def set_use_adjusted_values(self, use_adjusted):
        self.__use_adjusted_values = use_adjusted

    def append(self, bar):
        self.append_with_date_time(bar.get_date_time(), bar)

    def append_with_date_time(self, date_time, bar):
        assert(date_time is not None)
        assert(bar is not None)
        bar.set_use_adjusted_value(self.__use_adjusted_values)

        super(BarDataSeries, self).append_with_date_time(date_time, bar)
        self.__open_ds.append_with_date_time(date_time, bar.get_open())
        self.__close_ds.append_with_date_time(date_time, bar.get_close())
        self.__high_ds.append_with_date_time(date_time, bar.get_high())
        self.__low_ds.append_with_date_time(date_time, bar.get_low())
        self.__volume_ds.append_with_date_time(date_time, bar.get_volume())
        self.__adj_close_ds.append_with_date_time(date_time, bar.get_adj_close())

        # Process extra columns.
        for name, value in bar.get_extra_columns().iteritems():
            extra_ds = self.__get_or_create_extra_ds(name)
            extra_ds.append_with_date_time(date_time, value)

    def get_open_dataseries(self):
        """Returns a :class:`dataseries.DataSeries` with the open prices."""
        return self.__open_ds

    def get_close_dataseries(self):
        """Returns a :class:`dataseries.DataSeries` with the close prices."""
        return self.__close_ds

    def get_high_dataseries(self):
        """Returns a :class:`dataseries.DataSeries` with the high prices."""
        return self.__high_ds

    def get_low_dataseries(self):
        """Returns a :class:`dataseries.DataSeries` with the low prices."""
        return self.__low_ds

    def get_volume_dataseries(self):
        """Returns a :class:`dataseries.DataSeries` with the volume."""
        return self.__volume_ds

    def get_adj_close_dataseries(self):
        """Returns a :class:`dataseries.DataSeries` with the adjusted close prices."""
        return self.__adj_close_ds

    def get_price_dataseries(self):
        """Returns a :class:`dataseries.DataSeries` with the close or adjusted close prices."""
        if self.__use_adjusted_values:
            return self.__adj_close_ds
        else:
            return self.__close_ds

    def get_extra_dataseries(self, name):
        """Returns a :class:`dataseries.DataSeries` for an extra column."""
        return self.__get_or_create_extra_ds(name)